package com.chenziwen.scala.chapter08

object Scala15_Match4 {
  def main(args: Array[String]): Unit = {
    // 样例类
    // 当声明一个样例类时，如下几件事会自动发生
    // 1.构造器中的每一个参数都成为val,除非它被显式的被声明为var（不建议这样做）
    // 2.在伴生对象中提供apply方法让你不用new关键字就能构造出响应的对象，比如Dollar(29.95)或Currency(29.95, "EUR")
    // 3.提供unapply方法（提取器：提取apply方法传入的参数）让模式匹配可以工作
    // 4.将生成toString、equals、hashCode和copy方法，除非显式的给出这些方法的定义
    for (amt <- Array(Dollar(1000.0), Currency(1000.0, "EUR"), Nothing)) {
      val result = amt match {
        case Dollar(v) => "$" + v
        case Currency(_, u) => u
        case Nothing => ""
      }
      println(amt + ": " + result)
    }

    // 样例类的copy方法
    val c = Currency(1000.0, "EUR")
    val c1 = c.copy(unit = "RMB")
    println(c1)

    val sale = Bundle("书籍", 10, Article("漫画", 40), Bundle("文学作品", 20, Article("《阳关》", 80), Article("《围城》", 30)))

    val result1 = sale match {
      case Bundle(_, _, Article(descr, _), _*) => descr
    }
    println(result1)

    val result2 = sale match {
      case Bundle(_, _, art@Article(_, _), rest) => (art, rest)
    }
    println(result2)

    def price(it: Item): Double = {
      it match {
        case Article(_, p) => p
        case Bundle(_, disc, its@_*) => its.map(price _).sum - disc
      }
    }
    println(price(sale))
  }
}

// sealed修饰的类成为密封类，那么这个类的样例类必须写在同一个源码文件中
abstract sealed class Amount

case class Dollar(value: Double) extends Amount

case class Currency(value: Double, unit: String) extends Amount

case object Nothing extends Amount

abstract class Item

case class Article(description: String, price: Double) extends Item

case class Bundle(description: String, discount: Double, item: Item*) extends Item

